关于python:Cython 0.2:prange意外降低了代码速度 | 您所在的位置:网站首页 › cython python › 关于python:Cython 0.2:prange意外降低了代码速度 |
在两种情况下考虑优化的cython代码: 123456 for j in xrange(8): for x in xrange(1, 600): tmp[j] = 0.0 for y in xrange(1, 800): tmp[j] += mag[j, x - 1, y - 1] hgi_out[j, x, y] = tmp[j] + hgi_out[j, x - 1, y]和: 123456 for j in prange(8): # < prange used for parallelization with openmp for x in xrange(1, 600): tmp[j] = 0.0 for y in xrange(1, 800): tmp[j] += mag[j, x - 1, y - 1] hgi_out[j, x, y] = tmp[j] + hgi_out[j, x - 1, y]在两种情况下,代码都在具有nogil声明的本地函数和具有内存视图和优化布局的numpy数组中。第一种情况的基准运行时间为14.97毫秒,而第二种情况的运行时间为26.64,几乎翻了一番! 除上述情况外,我还有其他功能可以使用prange大大提高多核计算机上的性能,我不知道发生了什么。 关于为什么prange会使代码变慢的任何想法? FWIW,这是完整的原始代码: 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152# cython: boundscheck=False # cython: wraparound=False # cython: nonecheck=False # cython: overflowcheck.fold=True # cython: embedsignature=False # cython: cdivision=True # cython: cdivision_warnings=False # cython: always_allow_keywords=False # cython: profile=False # cython: linetrace=False # cython: infer_types=False # cython: language_level=2 # cython: c_string_type=unicode # cython: c_string_encoding=utf-8 # cython: type_version_tag=True # cython: unraisable_tracebacks=True from __future__ import division import numpy as np cimport numpy as np cimport cython from cython.parallel import prange DTYPE = np.int ctypedef np.int_t DTYPE_t UITYPE = np.uint ctypedef np.uint_t UITYPE_t U8TYPE = np.uint8 ctypedef np.uint8_t U8TYPE_t F32TYPE = np.float32 ctypedef np.float32_t F32TYPE_t F64TYPE = np.float64 ctypedef np.float64_t F64TYPE_t ctypedef Py_ssize_t DSIZE_t cdef void native_hog_integral_b(F64TYPE_t [:, :, ::1] mag, F64TYPE_t [:, :, ::1] hgi_out) nogil: cdef DSIZE_t m, n, x, y, j, dims = mag.shape[0] cdef F64TYPE_t [32] tmp cdef F64TYPE_t val = 0 m, n = mag.shape[1] + 1, mag.shape[2] + 1 for j in prange(dims): for x in xrange(1, m): tmp[j] = 0.0 for y in xrange(1, n): tmp[j] += mag[j, x - 1, y - 1] hgi_out[j, x, y] = tmp[j] + hgi_out[j, x - 1, y] def hog_integral_b(mag, hgi_out=None, orientations=8): if hgi_out is None: hgi_out = np.zeros((orientations + 1, mag.shape[0] + 1, mag.shape[1] + 1), dtype=F64TYPE) native_hog_integral_b(mag, hgi_out) return hgi_out要测试以上代码,请尝试: 123mg2 = np.random.rand(9, 600, 800).astype(F64TYPE) hg2 = np.zeros((9, mg2.shape[1] + 1, mg2.shape[2] + 1), dtype=F64TYPE) print timeit(lambda:hog_integral_b(mg2, hgi_out=hg2), number=10)更新: 好的,我仔细查看了setup.py编译器选项: 1234567891011121314151617from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext import numpy as np ext_modules = [Extension("hog_cy", ["hog_cy.pyx"], #extra_compile_args = ["-O3","-fopenmp","-fno-strict-aliasing"], extra_compile_args = ["-O3","-fopenmp"], extra_link_args=["-fopenmp"] )] setup ( name = 'performance test app', cmdclass = {'build_ext': build_ext}, include_dirs = [np.get_include()], ext_modules = ext_modules, )选项-fno-strict-aliasing似乎引起了问题,关闭电源后,我没有加速,也没有损失。 相关讨论 你能发表一个完整的例子吗? 我希望问题变得更清楚,发布整个代码。 很抱歉如此,但是您可以添加一个函数来调用形状和dtype正确的样本(随机)数据的hog_integral_b吗? 好,我会做的,给我一些时间 好了,最后用测试代码回答更新 使用您的代码prange在我的计算机上的@ user698585比range更快 @Castro:你在跟我开玩笑!我将在一个单独的程序包中再次检查代码,这可能与编译器选项有关,说到其中,您使用了什么? 在我的时代是一样的 @ Castro,E先生:我在使用mingw和python2.7 32位的Windows7 64位计算机上。我正在使用" -O3"和" -fopenmp"编译器选项,您的选择是什么? @Mr E:也许您没有正确配置openmp,请确保您在其他基准测试中获得了一些提速 @ user698585出于好奇,将OMP_NUM_THREADS环境变量设置为什么? @JoshAdel:设置为2,检查我的更新 groups.google.com/forum/#!forum/cython-users-您可以尝试使用此方法以获得更好/更完整的答案:cython团队会及时做出回应您正在进行GIL战斗,因为prange不在nogil块内。您的代码中没有并发性,只有多个线程竞争GIL所有权: 123456789101112131415161718cimport cython from cython.parallel cimport prange, parallel cdef void native_hog_integral_b(F64TYPE_t [:, :, ::1] mag, F64TYPE_t [:, :, ::1] hgi_out): cdef DSIZE_t m, n, j, dims = mag.shape[0] cdef F64TYPE_t val = 0 m, n = mag.shape[1] + 1, mag.shape[2] + 1 with nogil, parallel(): cdef DSIZE_t x, y cdef F64TYPE_t tmp for j in prange(dims): for x in range(1, m): tmp = 0.0 for y in range(1, n): tmp += mag[j, x - 1, y - 1] hgi_out[j, x, y] = tmp + hgi_out[j, x - 1, y] 相关讨论 原生函数(native_hog_integral_b)在其签名的末尾带有nogil声明,该声明模式对于其他函数也非常适用(上面的代码未显示)。我在想,也许编译器没有考虑将某些内部变量视为本地线程安全的(例如tmp),但还没有尝试过。 函数的nogil声明不需要释放GIL,也不需要释放GIL,它允许在nogil块内使用该函数。您可以在按住GIL的同时使用nogil函数。除非您键入" with nogil",否则不会释放GIL: 123456789101112131415161718cimport cython from cython.parallel cimport prange, parallel cdef void native_hog_integral_b(F64TYPE_t [:, :, ::1] mag, F64TYPE_t [:, :, ::1] hgi_out): cdef DSIZE_t m, n, j, dims = mag.shape[0] cdef F64TYPE_t val = 0 m, n = mag.shape[1] + 1, mag.shape[2] + 1 with nogil, parallel(): cdef DSIZE_t x, y cdef F64TYPE_t tmp for j in prange(dims): for x in range(1, m): tmp = 0.0 for y in range(1, n): tmp += mag[j, x - 1, y - 1] hgi_out[j, x, y] = tmp + hgi_out[j, x - 1, y] |
CopyRight 2018-2019 实验室设备网 版权所有 |